{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import keras\n",
    "import numpy as np\n",
    "from keras.models import Sequential\n",
    "from keras.layers import Dense,LSTM,Dropout\n",
    "from sklearn.preprocessing import MinMaxScaler\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "def create_dataset(signal_data,look_back=1):\n",
    "    dataX,dataY=[],[]\n",
    "    for i in range(len(signal_data)-look_back):\n",
    "        dataX.append(signal_data[i:(i+look_back),0])\n",
    "        dataY.append(signal_data[i+look_back,0])\n",
    "    return np.array(dataX),np.array(dataY)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "class CustomHistory(keras.callbacks.Callback):\n",
    "    def init(self):\n",
    "        self.train_loss=[]\n",
    "        self.val_loss=[]\n",
    "    def on_epoch_end(self,batch,logs={}):\n",
    "        self.train_loss.append(logs.get('loss'))\n",
    "        self.val_loss.append(logs.get('val_loss'))\n",
    "        \n",
    "look_back=40"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "signal_data=np.cos(np.arange(1600)*(20*np.pi/1000))[:,None]\n",
    "scaler=MinMaxScaler(feature_range=(0,1))\n",
    "signal_data=scaler.fit_transform(signal_data)\n",
    "\n",
    "train=signal_data[0:800]\n",
    "val=signal_data[800:1200]\n",
    "test=signal_data[1200:]\n",
    "\n",
    "x_train,y_train=create_dataset(train,look_back)\n",
    "x_val,y_val=create_dataset(val,look_back)\n",
    "x_test,y_test=create_dataset(test,look_back)\n",
    "\n",
    "x_train=np.reshape(x_train,(x_train.shape[0],x_train.shape[1],1))\n",
    "x_val=np.reshape(x_val,(x_val.shape[0],x_val.shape[1],1))\n",
    "x_test=np.reshape(x_test,(x_test.shape[0],x_test.shape[1],1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "model=Sequential()\n",
    "for i in range(2):\n",
    "    model.add(LSTM(32,batch_input_shape=(1,look_back,1),stateful=True,return_sequences=True))\n",
    "    model.add(Dropout(0.3))\n",
    "model.add(LSTM(32,batch_input_shape=(1,look_back,1),stateful=True))\n",
    "model.add(Dropout(0.3))\n",
    "model.add(Dense(1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "model.compile(loss='mean_squared_error',optimizer='adam')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "custom_hist=CustomHistory()\n",
    "custom_hist.init()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Train on 760 samples, validate on 360 samples\n",
      "Epoch 1/1\n",
      "760/760 [==============================] - 68s 90ms/step - loss: 0.0745 - val_loss: 0.1314\n",
      "Train on 760 samples, validate on 360 samples\n",
      "Epoch 1/1\n",
      "760/760 [==============================] - 74s 98ms/step - loss: 0.0956 - val_loss: 0.0178\n",
      "Train on 760 samples, validate on 360 samples\n",
      "Epoch 1/1\n",
      "760/760 [==============================] - 70s 92ms/step - loss: 0.0124 - val_loss: 0.0074\n",
      "Train on 760 samples, validate on 360 samples\n",
      "Epoch 1/1\n",
      "197/760 [======>.......................] - ETA: 46s - loss: 0.0077"
     ]
    },
    {
     "ename": "KeyboardInterrupt",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mKeyboardInterrupt\u001b[0m                         Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-8-6c5c137897a0>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0mi\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m200\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m     \u001b[0mmodel\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mfit\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mx_train\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0my_train\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mepochs\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mbatch_size\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mshuffle\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mFalse\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mcallbacks\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mcustom_hist\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mvalidation_data\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mx_val\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0my_val\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m      3\u001b[0m     \u001b[0mmodel\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mreset_states\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32m~\\anaconda3\\envs\\mytf\\lib\\site-packages\\keras\\engine\\training.py\u001b[0m in \u001b[0;36mfit\u001b[1;34m(self, x, y, batch_size, epochs, verbose, callbacks, validation_split, validation_data, shuffle, class_weight, sample_weight, initial_epoch, steps_per_epoch, validation_steps, validation_freq, max_queue_size, workers, use_multiprocessing, **kwargs)\u001b[0m\n\u001b[0;32m   1237\u001b[0m                                         \u001b[0msteps_per_epoch\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0msteps_per_epoch\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1238\u001b[0m                                         \u001b[0mvalidation_steps\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mvalidation_steps\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m-> 1239\u001b[1;33m                                         validation_freq=validation_freq)\n\u001b[0m\u001b[0;32m   1240\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1241\u001b[0m     def evaluate(self,\n",
      "\u001b[1;32m~\\anaconda3\\envs\\mytf\\lib\\site-packages\\keras\\engine\\training_arrays.py\u001b[0m in \u001b[0;36mfit_loop\u001b[1;34m(model, fit_function, fit_inputs, out_labels, batch_size, epochs, verbose, callbacks, val_function, val_inputs, shuffle, initial_epoch, steps_per_epoch, validation_steps, validation_freq)\u001b[0m\n\u001b[0;32m    194\u001b[0m                     \u001b[0mins_batch\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mi\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mins_batch\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mi\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mtoarray\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    195\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 196\u001b[1;33m                 \u001b[0mouts\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mfit_function\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mins_batch\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    197\u001b[0m                 \u001b[0mouts\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mto_list\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mouts\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    198\u001b[0m                 \u001b[1;32mfor\u001b[0m \u001b[0ml\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mo\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mzip\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mout_labels\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mouts\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32m~\\anaconda3\\envs\\mytf\\lib\\site-packages\\tensorflow_core\\python\\keras\\backend.py\u001b[0m in \u001b[0;36m__call__\u001b[1;34m(self, inputs)\u001b[0m\n\u001b[0;32m   3725\u001b[0m         \u001b[0mvalue\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mmath_ops\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcast\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mvalue\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mtensor\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdtype\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   3726\u001b[0m       \u001b[0mconverted_inputs\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mvalue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m-> 3727\u001b[1;33m     \u001b[0moutputs\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_graph_fn\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m*\u001b[0m\u001b[0mconverted_inputs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m   3728\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   3729\u001b[0m     \u001b[1;31m# EagerTensor.numpy() will often make a copy to ensure memory safety.\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32m~\\anaconda3\\envs\\mytf\\lib\\site-packages\\tensorflow_core\\python\\eager\\function.py\u001b[0m in \u001b[0;36m__call__\u001b[1;34m(self, *args, **kwargs)\u001b[0m\n\u001b[0;32m   1549\u001b[0m       \u001b[0mTypeError\u001b[0m\u001b[1;33m:\u001b[0m \u001b[0mFor\u001b[0m \u001b[0minvalid\u001b[0m \u001b[0mpositional\u001b[0m\u001b[1;33m/\u001b[0m\u001b[0mkeyword\u001b[0m \u001b[0margument\u001b[0m \u001b[0mcombinations\u001b[0m\u001b[1;33m.\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1550\u001b[0m     \"\"\"\n\u001b[1;32m-> 1551\u001b[1;33m     \u001b[1;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_call_impl\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m   1552\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1553\u001b[0m   \u001b[1;32mdef\u001b[0m \u001b[0m_call_impl\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mcancellation_manager\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mNone\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32m~\\anaconda3\\envs\\mytf\\lib\\site-packages\\tensorflow_core\\python\\eager\\function.py\u001b[0m in \u001b[0;36m_call_impl\u001b[1;34m(self, args, kwargs, cancellation_manager)\u001b[0m\n\u001b[0;32m   1589\u001b[0m       raise TypeError(\"Keyword arguments {} unknown. Expected {}.\".format(\n\u001b[0;32m   1590\u001b[0m           list(kwargs.keys()), list(self._arg_keywords)))\n\u001b[1;32m-> 1591\u001b[1;33m     \u001b[1;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_call_flat\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcaptured_inputs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mcancellation_manager\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m   1592\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1593\u001b[0m   \u001b[1;32mdef\u001b[0m \u001b[0m_filtered_call\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32m~\\anaconda3\\envs\\mytf\\lib\\site-packages\\tensorflow_core\\python\\eager\\function.py\u001b[0m in \u001b[0;36m_call_flat\u001b[1;34m(self, args, captured_inputs, cancellation_manager)\u001b[0m\n\u001b[0;32m   1690\u001b[0m       \u001b[1;31m# No tape is watching; skip to running the function.\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1691\u001b[0m       return self._build_call_outputs(self._inference_function.call(\n\u001b[1;32m-> 1692\u001b[1;33m           ctx, args, cancellation_manager=cancellation_manager))\n\u001b[0m\u001b[0;32m   1693\u001b[0m     forward_backward = self._select_forward_and_backward_functions(\n\u001b[0;32m   1694\u001b[0m         \u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32m~\\anaconda3\\envs\\mytf\\lib\\site-packages\\tensorflow_core\\python\\eager\\function.py\u001b[0m in \u001b[0;36mcall\u001b[1;34m(self, ctx, args, cancellation_manager)\u001b[0m\n\u001b[0;32m    543\u001b[0m               \u001b[0minputs\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    544\u001b[0m               \u001b[0mattrs\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"executor_type\"\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mexecutor_type\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m\"config_proto\"\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mconfig\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 545\u001b[1;33m               ctx=ctx)\n\u001b[0m\u001b[0;32m    546\u001b[0m         \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    547\u001b[0m           outputs = execute.execute_with_cancellation(\n",
      "\u001b[1;32m~\\anaconda3\\envs\\mytf\\lib\\site-packages\\tensorflow_core\\python\\eager\\execute.py\u001b[0m in \u001b[0;36mquick_execute\u001b[1;34m(op_name, num_outputs, inputs, attrs, ctx, name)\u001b[0m\n\u001b[0;32m     59\u001b[0m     tensors = pywrap_tensorflow.TFE_Py_Execute(ctx._handle, device_name,\n\u001b[0;32m     60\u001b[0m                                                \u001b[0mop_name\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0minputs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mattrs\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 61\u001b[1;33m                                                num_outputs)\n\u001b[0m\u001b[0;32m     62\u001b[0m   \u001b[1;32mexcept\u001b[0m \u001b[0mcore\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_NotOkStatusException\u001b[0m \u001b[1;32mas\u001b[0m \u001b[0me\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     63\u001b[0m     \u001b[1;32mif\u001b[0m \u001b[0mname\u001b[0m \u001b[1;32mis\u001b[0m \u001b[1;32mnot\u001b[0m \u001b[1;32mNone\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mKeyboardInterrupt\u001b[0m: "
     ]
    }
   ],
   "source": [
    "for i in range(200):\n",
    "    model.fit(x_train,y_train,epochs=1,batch_size=1,shuffle=False,callbacks=[custom_hist],validation_data=(x_val,y_val))\n",
    "    model.reset_states()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.plot(custom_hist.train_loss)\n",
    "plt.plot(custom_hist.val_loss)\n",
    "plt.ylim(0.0,0.15)\n",
    "plt.ylabel('loss')\n",
    "plt.xlabel('epoch')\n",
    "plt.legend(['train','val'],loc='upper left')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "look_ahead=250\n",
    "xhat=x_test[0]\n",
    "predictions=np.zeros((look_ahead,1))\n",
    "for i in range(look_ahead):\n",
    "    prediction=model.preiction(np.array([xhat]),batch_size=1)\n",
    "    predictions[i]=prediction\n",
    "    xhat=np.vstack([xhat[1:],prediction])\n",
    "    \n",
    "plt.figure(figsize=(12,5))\n",
    "plt.plot(np.arange(look_ahead),predictions,'r',label='prediction')\n",
    "plt.plot(np.arange(look_ahead),_test[:look_ahead],label='test_function')\n",
    "plt.legend()\n",
    "plt.show()\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
